package com.neusoft.bizcore.activiti.service.impl;

import java.util.List;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.constants.BizcoreActivitiConstants;
import com.neusoft.bizcore.activiti.converter.ProcessConverter;
import com.neusoft.bizcore.activiti.dto.ProcessDTO;
import com.neusoft.bizcore.activiti.model.Process;
import com.neusoft.bizcore.activiti.repository.ProcessRepository;
import com.neusoft.bizcore.activiti.service.MoldDefinitionService;
import com.neusoft.bizcore.activiti.service.ProcessService;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;

@Service
public class ProcessServiceImpl implements ProcessService {

    @Autowired
    private ProcessRepository processRepository;
    @Autowired
    private ProcessConverter processConverter;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private MoldDefinitionService processDefinitionService;

    @Override
    public List<ProcessDTO> index(final Searchable searchable) {
        final List<Process> models = this.processRepository.index(searchable);
        return this.processConverter.toListDTO(models);
    }

    @Override
    public Page<ProcessDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<Process> result = this.processRepository.search(pageable, searchable);
        final Page<ProcessDTO> pageResult = this.processConverter.toPageDTO(result);
        pageResult.getContent().stream().forEach(ele -> {
            final ProcessDefinition data = this.repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(ele.getCode()).latestVersion().singleResult();
            if (data != null) {
                ele.setIsExist(true);
            } else {
                ele.setIsExist(false);
            }
        });
        return pageResult;
    }

    @Override
    public ProcessDTO create(final ProcessDTO dto) {

        final Process model = this.processConverter.toModel(dto);

        final Process check = this.processRepository.findByCode(dto.getCode());

        if (null != check) {
            throw new UnitedException(BizcoreActivitiConstants.PROCESS_CODE_NOT_REPEAT);
        }

        this.processRepository.save(model);

        return this.processConverter.toDTO(model);
    }

    @Override
    @Transactional
    public ProcessDTO update(final Long id, final ProcessDTO dto) {

        final Process check = this.processRepository.findByCode(dto.getCode());

        if ((null != check) && (check.getId().longValue() != id.longValue())) {
            throw new UnitedException(BizcoreActivitiConstants.PROCESS_CODE_NOT_REPEAT);
        }

        Process model;
        try {
            model = this.processRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        dto.setId(model.getId());
        this.processConverter.toModel(dto);
        this.processRepository.save(model);

        return this.processConverter.toDTO(model);
    }

    @Override
    public ProcessDTO details(final Long id) {

        final Process model;
        try {
            model = this.processRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final ProcessDTO result = this.processConverter.toDTO(model);

        final ProcessDefinition data = this.repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(model.getCode()).latestVersion().singleResult();
        if (data != null) {
            result.setIsExist(true);
        } else {
            result.setIsExist(false);
        }
        return result;
    }

    @Override
    @Transactional
    public void delete(final Long id) {

        final Process model;
        try {
            model = this.processRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 删除流程
        this.processDefinitionService.delete(model.getCode());

        // 删除流程定义
        this.processRepository.deleteById(id);
    }

    @Override
    public ProcessDTO details(final String code) {
        Process model;
        try {
            model = this.processRepository.findByCode(code);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {code });
        }
        return this.processConverter.toDTO(model);
    }

}
